﻿using Microsoft.Extensions.Options;
using Microsoft.Playwright;
using System;
using TableTools.Options;

namespace TableTools.Handlers
{
    public class BrowserHandler : IBrowserHandler
    {
        public BrowserHandler(ILogger<BrowserHandler> logger,
            IOptions<BrowserOptions> options)
        {
            _logger = logger;
            _options = options;
        }

        protected IPlaywright Playwright { get; private set; }

        protected IBrowser Browser { get; private set; }

        protected IBrowserContext BrowserContext { get; private set; }

        private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);

        private readonly ILogger<BrowserHandler> _logger;
        private readonly IOptions<BrowserOptions> _options;

        private async Task<IBrowserContext> GetBrowserContextAsync()
        {
            if (BrowserContext != null)
            {
                return BrowserContext;
            }

            try
            {
                await _semaphoreSlim.WaitAsync();

                if (BrowserContext != null)
                {
                    return BrowserContext;
                }

                this.Playwright = await Microsoft.Playwright.Playwright.CreateAsync();

                switch (_options.Value.BrowserType)
                {
                    case Shared.BrowserType.Webkit:
                        this.Browser = await Playwright.Webkit.LaunchAsync(new BrowserTypeLaunchOptions()
                        {
                            Headless = !_options.Value.IsShowBrowser,
                            SlowMo = 100,
                            Env = new Dictionary<string, string>()
                            {
                                ["PWDEBUG"] = "1"
                            }
                        });
                        break;
                    case Shared.BrowserType.Chrome:
                        this.Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions()
                        {
                            Headless = !_options.Value.IsShowBrowser,
                            Channel = "chrome",
                            SlowMo = 100,
                            Env = new Dictionary<string, string>()
                            {
                                ["PWDEBUG"] = "1"
                            },
                            ChromiumSandbox = true,
                        });
                        break;
                    case Shared.BrowserType.Edge:
                        this.Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions()
                        {
                            Headless = !_options.Value.IsShowBrowser,
                            Channel = "msedge",
                            SlowMo = 100,
                            Env = new Dictionary<string, string>()
                            {
                                ["PWDEBUG"] = "1"
                            },
                            ChromiumSandbox = true,
                        });
                        break;
                    case Shared.BrowserType.Firefox:
                        this.Browser = await Playwright.Firefox.LaunchAsync(new BrowserTypeLaunchOptions()
                        {
                            Headless = !_options.Value.IsShowBrowser,
                            SlowMo = 100,
                            Env = new Dictionary<string, string>()
                            {
                                ["PWDEBUG"] = "1"
                            },
                            ChromiumSandbox = true,
                        });
                        break;
                }


                var browserContext = await Browser.NewContextAsync(new BrowserNewContextOptions()
                {
                    ColorScheme = ColorScheme.Light,
                    ViewportSize = new()
                    {
                        Width = 1920,
                        Height = 1080
                    },
                    //BaseURL = "https://hl.alipay.com",
                });

                await browserContext.Tracing.StartAsync(new TracingStartOptions()
                {
                    Screenshots = true,
                    Snapshots = true,
                    Sources = true
                });
                return browserContext;
            }
            catch (Exception e)
            {
                _logger.LogError(e, "获取BrowserContext错误");
                throw;
            }
            finally
            {
                _semaphoreSlim.Release();
            }
        }

        public async Task<IPage> GetPageAsync()
        {
            var browserContext = await GetBrowserContextAsync();
            return await browserContext.NewPageAsync();
        }

        public void Dispose()
        {
            this.Playwright?.Dispose();
            this.Playwright = null;
            this.Browser?.DisposeAsync();
            this.Browser = null;
            this.BrowserContext?.DisposeAsync();
            this.BrowserContext = null;
        }
    }
}
